// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameplayCueManager.h"

#include "LyraGameplayCueManager.generated.h"

class FString;
class UClass;
class UObject;
class UWorld;
/** FObjectKey is an immutable, copyable key which can be used to uniquely identify an object for the lifetime of the application */

/** FObjectKey是不可变得，可复制的Key，在被用于唯一认证一个对象在整个应用的声明周期过程中。 */
struct FObjectKey;

/**
 * ULyraGameplayCueManager
 *
 * Game-specific manager for gameplay cues
 */

/**
 * ULyraGameplayCueManager
 * 
 * 针对GCue的游戏具体管理器。
 */
UCLASS()
class ULyraGameplayCueManager : public UGameplayCueManager
{
	GENERATED_BODY()

public:
	ULyraGameplayCueManager(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

	static ULyraGameplayCueManager* Get();

	//~UGameplayCueManager interface
	/** Called when manager is first created */

	/** 当管理器首次被创建时调用。 */
	virtual void OnCreated() override;

	/** 是否应该在运行期间异步加载对象库。 */
	virtual bool ShouldAsyncLoadRuntimeObjectLibraries() const override;

	/** 是否应该同步导入缺失GCue。 */
	virtual bool ShouldSyncLoadMissingGameplayCues() const override;

	/** 是否应该异步导入确实GCue。 */
	virtual bool ShouldAsyncLoadMissingGameplayCues() const override;
	//~End of UGameplayCueManager interface

	static void DumpGameplayCues(const TArray<FString>& Args);

	// When delay loading cues, this will load the cues that must be always loaded anyway

	// 当延迟加载GCue时，这将导入GCue，必须无论如何经常导入GCue。

	// NOTE: 当延迟加载GCue时，这将无论如何都必须加载GCue。
	void LoadAlwaysLoadedCues();

	// Updates the bundles for the singular gameplay cue primary asset

	// 更新资源包，对于单个的GCue原始资源。
	void RefreshGameplayCuePrimaryAsset();

private:
	void OnGameplayTagLoaded(const FGameplayTag& Tag);
	void HandlePostGarbageCollect();
	void ProcessLoadedTags();

	/** 处理标签预加载。 */
	void ProcessTagToPreload(const FGameplayTag& Tag, UObject* OwningObject);
	void OnPreloadCueComplete(FSoftObjectPath Path, TWeakObjectPtr<UObject> OwningObject, bool bAlwaysLoadedCue);
	/** 注册预加载GCue。 */
	void RegisterPreloadedCue(UClass* LoadedGameplayCueClass, UObject* OwningObject);
	void HandlePostLoadMap(UWorld* NewWorld);
	void UpdateDelayLoadDelegateListeners();

	/** 是否应该延迟加载GCue。 */
	bool ShouldDelayLoadGameplayCues() const;

private:
	struct FLoadedGameplayTagToProcessData
	{
		FGameplayTag Tag;
		TWeakObjectPtr<UObject> WeakOwner;

		FLoadedGameplayTagToProcessData() {}
		FLoadedGameplayTagToProcessData(const FGameplayTag& InTag, const TWeakObjectPtr<UObject>& InWeakOwner) : Tag(InTag), WeakOwner(InWeakOwner) {}
	};

private:
	// Cues that were preloaded on the client due to being referenced by content

	// GCue将会被预导入到客户端，由于内容被引用。

	/// Property is transient: shouldn't be saved, zero-filled at load time.

	/// 属性是瞬时的：不会被保存，加载时被0填充。
	UPROPERTY(transient)
	TSet<TObjectPtr<UClass>> PreloadedCues;
	TMap<FObjectKey, TSet<FObjectKey>> PreloadedCueReferencers;

	// Cues that were preloaded on the client and will always be loaded (code referenced or explicitly always loaded)

	// GCue是被预加载在客户端并且经常被加载(代码引用或经常明确地加载)。
	UPROPERTY(transient)
	TSet<TObjectPtr<UClass>> AlwaysLoadedCues;

	TArray<FLoadedGameplayTagToProcessData> LoadedGameplayTagsToProcess;
	/**
	 * This is the Windows version of a critical section. It uses an aggregate
	 * CRITICAL_SECTION to implement its locking.
	 * 
	 * typedef FWindowsCriticalSection FCriticalSection;
	 * 
	 * 这是临界区的Window版本。它使用一个融合CRITICAL_SECTION结构体实现锁机制。
	 */
	FCriticalSection LoadedGameplayTagsToProcessCS;
	bool bProcessLoadedTagsAfterGC = false;
};
